package design.LRU;

import java.util.HashMap;

/**
 * 运用你所掌握的数据结构，设计和实现一个  LRU (最近最少使用) 缓存机制 。
 * 实现 LRUCache 类：
 *
 * LRUCache(int capacity) 以正整数作为容量 capacity 初始化 LRU 缓存
 * int get(int key) 如果关键字 key 存在于缓存中，则返回关键字的值，否则返回 -1 。
 * void put(int key, int value) 如果关键字已经存在，则变更其数据值；如果关键字不存在，则插入该组「关键字-值」。当缓存容量达到上限时，它应该在写入新数据之前删除最久未使用的数据值，从而为新的数据值留出空间。
 *  
 */
public class LRUCache2 {
    private final HashMap<Integer, Node> map;
    private final DoubleList cache;
    private final int cap;
    public LRUCache2(int capacity) {
        this.cap = capacity;
        this.map = new HashMap<>();
        this.cache = new DoubleList();
    }

    public int get(int key) {
        if(!map.containsKey(key)){
            return -1;
        }
        Node node = map.get(key);
        makeRecently(key);
        return node.v;

    }

    public void put(int key, int value) {
        if(map.containsKey(key)){
            deleteNode(key);
            addRecently(key,value);
            return;
        }
        if(cache.size == cap){
            deleteLeast();
        }
        addRecently(key,value);

    }

    public void makeRecently(int key){
        Node node = map.get(key);
        cache.deleteNode(node);
        cache.addLast(node);
    }

    public void addRecently(int key,int value){
        Node node = new Node(key,value);
        map.put(key,node);
        cache.addLast(node);
    }


    public void deleteNode(int key){
        Node node = map.get(key);
        cache.deleteNode(node);
        map.remove(key);

    }

    public void deleteLeast(){
        Node node = cache.removeFirst();
        map.remove(node.k);

    }




    class DoubleList{
        private Node head;
        private Node tail;
        private int size;
        DoubleList(){
            head = new Node(0,0);
            tail = new Node(0,0);
            head.next = tail;
            tail.pre = head;
            size = 0;
        }

        public Node removeFirst(){
            if(head.next == tail){
                return null;
            }
            Node first = head.next;
            Node next = first.next;
            head.next = next;
            next.pre = head;
            size--;
            return first;
        }

        public void deleteNode(Node node){
            Node pre = node.pre;
            Node next = node.next;
            pre.next = next;
            next.pre = pre;
            size--;
        }

        public void addLast(Node node){
            Node pre = tail.pre;
            tail.pre = node;
            pre.next = node;
            node.pre = pre;
            node.next = tail;
            size++;
        }

        public int getSize(){
            return size;
        }


    }
    static class Node{
        private int k;
        private int v;
        public Node pre;
        public Node next;
        public Node(int k, int v){
            this.k = k;
            this.v = v;
        }
    }
}
